package com.example.myapplication;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer;

import android.opengl.GLUtils;
import android.util.Log;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

public class GLRender implements Renderer {

    private Bitmap mBitmapTexture = null;
    int mTexture[];

    float[] verticesRect = {
            1.0f, 1.0f, 0.0f,       // 0 - top right
            -1.0f, 1.0f, 0.0f,      // 1 - top left
            1.0f, -1.0f, 0.0f,      // 2 - bottom right
            -1.0f, -1.0f, 0.0f      // 3 - bottom left
    };

    float[] normalsRect = {
            0.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 1.0f,
    };

    float[] texCoordsRect = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f
    };

    private FloatBuffer vRectBuffer;
    private FloatBuffer nRectBuffer;
    private FloatBuffer tRectBuffer;

    public GLRender(Context context)
    {
        vRectBuffer = GLBufferWrapper.WrapFloat(verticesRect);
        nRectBuffer = GLBufferWrapper.WrapFloat(normalsRect);
        tRectBuffer = GLBufferWrapper.WrapFloat(texCoordsRect);

        mBitmapTexture = BitmapFactory.decodeResource(context.getResources(), R.drawable.texture);
        mTexture = new int[1];
    }

    @Override
    public void onDrawFrame(GL10 gl)
    {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);


        /* QUAD */
        gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        GLU.gluLookAt(gl, 0, 0, 3, 0, 0,0,
                0,1,0);

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vRectBuffer);

        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
        gl.glNormalPointer(GL10.GL_FLOAT, 0, nRectBuffer);

        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexture[0]);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, tRectBuffer);

        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    }

    private void setupLight(GL10 gl)
    {
        gl.glEnable(GL10.GL_LIGHTING);
        gl.glEnable(GL10.GL_LIGHT0);

        FloatBuffer light0Ambient = GLBufferWrapper.WrapFloat(new float[]{0.1f, 0.1f, 0.1f, 1.0f});
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, light0Ambient);

        FloatBuffer light0Diffuse = GLBufferWrapper.WrapFloat(new float[]{0.7f, 0.7f, 0.7f, 1.0f});
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, light0Diffuse);

        FloatBuffer light0Specular = GLBufferWrapper.WrapFloat(new float[]{0.7f, 0.7f, 0.7f, 1.0f});
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, light0Specular);

        FloatBuffer light0Position = GLBufferWrapper.WrapFloat(new float[]{0.0f, 10.0f, 10.0f, 0.0f});
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, light0Position);

        FloatBuffer light0Direction = GLBufferWrapper.WrapFloat(new float[]{0.0f, 0.0f, -1.0f});
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPOT_DIRECTION, light0Direction);

        gl.glLightf(GL10.GL_LIGHT0, GL10.GL_SPOT_CUTOFF, 45.0f);

    }

    private void setupTexture(GL10 gl)
    {
        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glEnable(GL10.GL_BLEND);
        gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ZERO);

        IntBuffer intBuffer = GLBufferWrapper.WrapInt(new int[]{1});
        gl.glGenTextures(1, intBuffer);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexture[0]);
        gl.glActiveTexture(GL10.GL_TEXTURE0);

        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);

        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmapTexture, 0);
    }

    private void setupMaterial(GL10 gl)
    {

        // 也可以用glEnable(GL_COLOR_MATERIAL)让opengl使用顶点颜色，但es 2.0后被移除了，使用shader即可。
        // 同时设置环境管和漫反射（也可以分开设置）
        FloatBuffer ambientAndDiffuse = GLBufferWrapper.WrapFloat(new float[]{0.0f, 0.1f, 0.9f, 1.0f});
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT_AND_DIFFUSE, ambientAndDiffuse);

        // 设置高光颜色
        FloatBuffer specular = GLBufferWrapper.WrapFloat(new float[]{0.9f, 0.9f, 0.0f, 1.0f});
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, specular);
        gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 25.0f);   // 反光度，愈高反光成都越小。

        // 设置自发光
        //FloatBuffer emission = GLBufferWrapper.WrapFloat(new float[]{0.0f, 0.4f, 0.0f, 1.0f});
        //gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_EMISSION, emission);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        Log.i("GLRender", "onSurfaceChanged:: w: " + width + " h: " + height);
        float ratio = (float)width/height;

        gl.glViewport(0,0,width,height);

        gl.glMatrixMode(GL10.GL_PROJECTION);

        gl.glLoadIdentity();;

        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    }

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        Log.i("GLRender", "opengl version: " + gl10.glGetString(GL10.GL_VERSION));

        gl10.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

        gl10.glClearColor(0.3F, 0.3F, 0.3F, 1.0F);      // 不要不写小数点！否则会没用。

        gl10.glEnable(GL10.GL_DEPTH_TEST);

        setupLight(gl10);
        setupMaterial(gl10);
        setupTexture(gl10);
    }
}

























